/******************************************************************************
 * Copyright (C) 2024 EternalChip, Inc.(Gmbh) or its affiliates.
 * 
 * All Rights Reserved.
 * 
 * @file bsp_key.c
 * 
 * @par dependencies 
 * - stdio.h
 * - stdint.h
 * 
 * @author Jack | R&D Dept. | EternalChip 立芯嵌入式
 * 
 * @brief Provide the HAL APIs of AHT21 and corresponding opetions.
 * 
 * Processing flow:
 * 
 * call directly.
 * 
 * @version V1.0 2024-11-25
 *
 * @note 1 tab == 2 spaces!
 * 
 *****************************************************************************/

#include "bsp_key.h"
#include <stdbool.h>

xQueueHandle Key_Queue = NULL;

#define KEY_DEBOUNCE_DELAY       10     /* 按键消抖延时     */
#define KEY_LONG_PRESS_DELAY     500    /* 按键长按检测延时 */ 
#define KEY_MULTI_PRESSED_DELAY  200    /* 双击按键检测延时 */
/**
 * @brief 实现读取按键状态的代码
 * 
 * @return KEY_PRESSED 、KEY_LONGPRESSED、KEY_RELEASED、 KEY_ERROR
 */
key_press_status_t read_key() {
    static key_press_status_t key_status = KEY_RELEASED;
    static uint32_t debounce_timer       = portMAX_DELAY;
    static uint32_t long_press_timer     = portMAX_DELAY;
    static uint32_t multi_press_timer    = portMAX_DELAY;
    static uint8_t  key_press_cnt        = 0;

    key_press_status_t ret_val  = KEY_RELEASED;
    uint32_t current_key_status = HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin);

    switch (key_status)
    {
    case KEY_RELEASED:
      /* 检测按键是否被按下 */
      if ( current_key_status == KEY_PRESSED ) 
      {
        key_status = KEY_DEBOUNCE;
        debounce_timer = osKernelGetTickCount() + KEY_DEBOUNCE_DELAY;
      }
      else  /* 按键释放判断 */
      {
        if ( osKernelGetTickCount() > multi_press_timer ) {
          if ( key_press_cnt == 1 ) {
            ret_val = KEY_PRESSED;
          } else if ( key_press_cnt >= 2 ) {
            ret_val = KEY_DOUBLE_PRESSED;
          }
          key_press_cnt = 0;
          multi_press_timer = portMAX_DELAY;
          long_press_timer  = portMAX_DELAY;
        }
      }
      break;
    case KEY_LONGPRESS:
      /* 检测长按是否松开 */
      if ( current_key_status == KEY_RELEASED ) {
        multi_press_timer = portMAX_DELAY;
        long_press_timer  = portMAX_DELAY;
        key_status = KEY_RELEASED;
      }
      break;
    case KEY_DEBOUNCE:
      if ( current_key_status == KEY_PRESSED ) 
      {
        if (osKernelGetTickCount() > debounce_timer) {  
          key_status = KEY_PRESSED;
          debounce_timer = portMAX_DELAY;
          long_press_timer = osKernelGetTickCount() + KEY_LONG_PRESS_DELAY;
        }
      }
      else 
      {
        key_status = KEY_RELEASED;
      }
      break;
    case KEY_PRESSED:
      if ( current_key_status == KEY_PRESSED )
      {
        if ( osKernelGetTickCount() > long_press_timer ) {
          ret_val    = KEY_LONGPRESS;
          key_status = KEY_LONGPRESS;
        }
      }
      else 
      {
        key_press_cnt += 1;
        printf("key_press_cnt = %d\r\n", key_press_cnt);
        multi_press_timer = osKernelGetTickCount() + KEY_MULTI_PRESSED_DELAY;
        long_press_timer  = osKernelGetTickCount() + KEY_LONG_PRESS_DELAY;
        key_status = KEY_RELEASED;
      }
      break;
    default:
      break;
    }
    return ret_val;
}


key_status_t key_scan(key_press_status_t* key_value) 
{
  uint32_t timeoutTicks = 0;
  key_press_status_t key_status = KEY_RELEASED;

  while (timeoutTicks++ < 1000) 
  {
    switch ( read_key() )
    {
    case KEY_PRESSED:
      key_status = KEY_PRESSED;
      *key_value = key_status;
      return KEY_OK;  
    case KEY_LONGPRESS:
      key_status = KEY_LONGPRESS;
      *key_value = key_status;
      return KEY_OK;
    case KEY_DOUBLE_PRESSED:
      printf("key_double_pressed\r\n");
      key_status = KEY_DOUBLE_PRESSED;
      *key_value = key_status;
      return KEY_OK;
    default:
      break;
    }
  }
  *key_value = key_status;
  return KEY_ERRORTIMEOUT;
}


/**
 * @brief 键盘任务函数，负责扫描键盘状态并处理按键事件
 * 
 * 本函数周期性地扫描键盘，检查键盘是否被按下。如果检测到按键事件，
 * 则通过队列发送按键状态。这是通过调用key_scan函数来完成的，如果键被按下，
 * 则向Key_Queue队列发送按键状态，通知其他任务或模块按键事件已发生。
 * 
 * @param argument 任务参数，未使用
 */
void Key_Task(void *argument) 
{
  key_status_t key_ret          = KEY_OK;
  key_press_status_t key_status = KEY_RELEASED;

  Key_Queue = xQueueCreate(10, sizeof(key_press_status_t));
  if ( NULL == Key_Queue ) {
    printf("Key_Queue Create Failed!\r\n");
  } else {
    printf("Key_Queue Create OK!\r\n");
  }

  for(;;)
  {
    // printf("Key_Task Running!\r\n");
    key_ret = key_scan(&key_status);
    if ( KEY_OK == key_ret ) 
    {
      switch (key_status)
      {
      case KEY_PRESSED:
        printf("Key Pressed!\r\n");
        if ( pdTRUE == xQueueSend(Key_Queue, &key_status, 0) ) {
          printf("Key Queue Send OK!\r\n");
        }
        break;
      case KEY_LONGPRESS:
        printf("Key Long Pressed!\r\n");
        if ( pdTRUE == xQueueSend(Key_Queue, &key_status, 0) ) {
          printf("Key Queue Send OK!\r\n");
        }
        break;
      case KEY_DOUBLE_PRESSED:
        printf("Key Double Pressed!\r\n");
        if ( pdTRUE == xQueueSend(Key_Queue, &key_status, 0) ) {
          printf("Key Queue Send OK!\r\n");
        }
        break;
      default:
        break;
      }
    }
    osDelay(10);
  }
}



